Skip to content

Conversation

@MuzzaiyyanHussain
Copy link

@MuzzaiyyanHussain MuzzaiyyanHussain commented Nov 12, 2025

Description

Fixes supabase/auth#2256getClaims(token, { allowExpired: true }) was still throwing an expiration error.

Change

  • Skip validateExp() when allowExpired=true to properly decode expired JWTs.

Checklist

@MuzzaiyyanHussain MuzzaiyyanHussain requested review from a team as code owners November 12, 2025 07:31
@coveralls
Copy link

coveralls commented Nov 12, 2025

Coverage Status

coverage: 95.367% (+13.8%) from 81.58%
when pulling 12b1094 on MuzzaiyyanHussain:fix-getClaims-allowExpired
into 1371057 on supabase:master.

@MuzzaiyyanHussain
Copy link
Author

@fenos

@mandarini mandarini changed the title Fix get claims allow expired fix(auth): getClaims allow expired Nov 12, 2025
@mandarini mandarini self-assigned this Nov 12, 2025
@mandarini
Copy link
Contributor

Hi @MuzzaiyyanHussain,

Thank you for investigating this issue! And thank you very much for your contribution. I've done some testing and found a few important things:

  1. Your change is functionally equivalent to the original

The change from !options?.allowExpired to options?.allowExpired !== true produces identical behavior. In this case, both conditions behave the same for our intended use: allowExpired is always a boolean, so the change doesn’t affect the logic. While !== true adds a bit of extra type safety, it’s not needed here. The underlying issue seems to be on the server side, not in this check.

  1. The real problem is server-side validation

The allowExpired option only controls client-side JWT expiration validation. However, when your JWT uses a symmetric algorithm (HS256, which is the default), the code takes a different path:

  1. Line 3657-3663: Checks if it can verify the JWT signature locally
  2. For HS256 tokens → signingKey is null (can't verify symmetric keys client-side)
  3. Line 3666-3669: Falls back to calling await this.getUser(token)
  4. The server validates the JWT, including expiration, and rejects expired tokens

So even though the client-side check is skipped with allowExpired: true, the server still rejects the expired token via the getUser() API call.

  1. The actual issue remains unfixed

Your PR doesn't address the root cause. The allowExpired option is essentially broken for symmetric JWTs because they require server validation.

So, I will be closing this PR, and I transferred the original issue on the auth side!

Again, thank you very very much for your contribution!

@mandarini mandarini closed this Nov 12, 2025
@MuzzaiyyanHussain
Copy link
Author

Thanks for transferring! I'd love to help on the server-side fix if needed, could you point me to where JWT validation happens?

@mandarini
Copy link
Contributor

mandarini commented Nov 13, 2025

I am already in the process of preparing a PR. I will tag you once I submit it. Thank you @MuzzaiyyanHussain
We are discussing this internally, and whether we want to support this behaviour in the first place. Thank you for bearing with us.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

getClaims allowExpired

3 participants